<%+cbi/valueheader%>
<%
local api = require "luci.passwall.api"
local appname = 'passwall'
local map = self.map

local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_trojan_plus = api.is_finded("trojan-plus")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")

local function get_core(field, candidates)
	local v = map:get("@global_subscribe[0]", field)
	if not v or v == "" then
		for _, c in ipairs(candidates) do
			if c[1] then return c[2] end
		end
	end
	return v
end

local ss_type = get_core("ss_type", {{has_ss,"shadowsocks-libev"},{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local trojan_type = get_core("trojan_type", {{has_trojan_plus,"trojan-plus"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local vmess_type = get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local vless_type = get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local hysteria2_type = get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{has_singbox,"sing-box"}})
-%>
<script src="<%=resource%>/view/<%=appname%>/qrcode.min.js"></script>
<script type="text/javascript">//<![CDATA[
	let has_singbox = "<%=has_singbox%>"
	let has_xray = "<%=has_xray%>"
	let has_hysteria2 = "<%=has_hysteria2%>"
	let ss_type = "<%=ss_type%>"
	let trojan_type = "<%=trojan_type%>"
	let vmess_type = "<%=vmess_type%>"
	let vless_type = "<%=vless_type%>"
	let hysteria2_type = "<%=hysteria2_type%>"

	function padright(str, cnt, pad) {
		return str + Array(cnt + 1).join(pad);
	}

	function b64EncodeUnicode(str) {
		return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
			return String.fromCharCode('0x' + p1);
		}));
	}

	function b64encutf8safe(str) {
		return b64EncodeUnicode(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '');
	}

	function b64DecodeUnicode(str) {
		return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
			return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
		}).join(''));
	}

	function b64decutf8safe(str) {
		var l;
		str = str.replace(/-/g, "+").replace(/_/g, "/");
		l = str.length;
		l = (4 - l % 4) % 4;
		if (l)
			str = padright(str, l, "=");
		return b64DecodeUnicode(str);
	}

	function b64encsafe(str) {
		return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '')
	}

	function b64decsafe(str) {
		const orig = str;
		try {
			str = str.replace(/-/g, "+").replace(/_/g, "/");
			const pad = (4 - str.length % 4) % 4;
			if (pad) str += "=".repeat(pad);
			return atob(str);
		} catch (e) {
			return orig;
		}
	}

	function dictvalue(d, key) {
		var v = d[key];
		if (typeof (v) === 'undefined' || v === '')
			return '';
		return b64decsafe(v);
	}

	function parseNodeUrl(url) {
		let protocol = url.substring(0, url.indexOf("://")) + ":"
		let str = "http" + url.substring(url.indexOf("://"))
		const parsedUrl = new URL(str);
		var r = {
			hash: parsedUrl.hash, // #asd
			host: parsedUrl.host, // localhost:257
			hostname: parsedUrl.hostname, // localhost
			port: parsedUrl.port, // 257
			search: parsedUrl.search, // ?asd=asd
			passwd: parsedUrl.username || parsedUrl.password // username
		};
		return r;
	}
	
	function genQrcode(btn, urlname, sid) {
		var qrcode_div = document.getElementById("qrcode_div");
		qrcode_div.style.display = null;
		document.getElementById("qrcode").innerHTML = "";
		var url = buildUrl(btn, urlname, sid);
		if (url) {
			var qrcode = new QRCode(document.getElementById("qrcode"), {
				width: 150,
				height: 150
			});
			qrcode.makeCode(url);
		}
	}

	function buildUrl(btn, urlname, sid) {
		var opt = {
			base: "cbid.passwall",
			client: true,
			get: function (opt) {
				var id = this.base + "." + opt;
				var obj = document.getElementsByName(id)[0] || document.getElementsByClassName(id)[0] || document.getElementById(id)
				if (obj) {
					return obj;
				} else {
					return null;
				}
			},
			getlist: function (opt) {
				var id = this.base + "." + opt;
				var objs = document.getElementsByName(id) || document.getElementsByClassName(id);
				var ret = [];
				if (objs) {
					for (var i = 0; i < objs.length; i++) {
						ret[i] = objs[i].value;
					}
				} else {
					alert("<%:Faltal on get option, please help in debug: %>" + opt);
				}
				return ret;
			},
			query: function (param, src, default_value) {
				var obj = this.get(src);
				if (obj) {
					var ret = "&" + param + "=";
					if (obj.type === "checkbox") {
						return ret + (obj.checked === true ? "1" : "0");
					} else {
						var result = encodeURIComponent(obj.value);
						if (result == null || result.trim() == "") {
							if (default_value) {
								return ret + default_value;
							}
							return "";
						} else {
							return ret + result;
						}
					}
				}
				return "";
			}
		}
		opt.base = "cbid." + urlname + "." + sid;
		opt.client = urlname.indexOf("server") === -1;
		var v_type = opt.get("type").value;
		var v_alias = opt.get("remarks");

		var dom_prefix = null
		var protocol = ""
		if (v_type === "SS") {
			dom_prefix = "ss_"
			protocol = "ss"
		} else if (v_type === "SS-Rust") {
			dom_prefix = "ssrust_"
			protocol = "ss"
		} else if (v_type === "SSR") {
			dom_prefix = "ssr_"
			protocol = "ssr"
		} else if (v_type === "Trojan-Plus") {
			dom_prefix = "trojan_plus_"
			protocol = "trojan"
		} else if (v_type === "Hysteria2") {
			dom_prefix = "hysteria2_"
			protocol = "hysteria2"
		} else if (v_type === "Xray") {
			dom_prefix = "xray_"
		} else if (v_type === "sing-box") {
			dom_prefix = "singbox_"
		}
		var _address = ""
		if (dom_prefix && dom_prefix != null) {
			try {
				var v_server = opt.get(dom_prefix + "address");
				const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
				if (ipv6Regex.test(v_server.value)) {
					_address = "[" + v_server.value + "]"
				} else {
					_address = v_server.value
				}
			} catch (e) {
			}
		}
		var url = null;
		if (v_type === "SS" || v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
			protocol = "ss"
			var v_port = opt.get(dom_prefix + "port");
			var v_method = opt.get(dom_prefix + "method") || opt.get(dom_prefix + "ss_method");
			var v_password = opt.get(dom_prefix + "password");

			url = b64encsafe(v_method.value + ":" + v_password.value) + "@" +
				_address + ":" +
				v_port.value + "/?";
			
			var shadow_tls;
			//生成SS Shadow-TLS 插件参数
			const generateShadowTLSBase64 = function(paramStr) {
				try {
					let obj = {};
					let list = paramStr.split(";");
					for (let i = 0; i < list.length; i++) {
						let kv = list[i].split("=");
						if (kv.length === 2) {
							let k = kv[0].trim(), v = kv[1].trim();
							let m = k.match(/^v(\d+)$/);
							if (m && v === "1") obj.version = m[1];
							else if (k === "passwd") obj.password = v;
							else obj[k] = v;
						}
					}
					return b64encsafe(JSON.stringify(obj));
				} catch (e) {
					return "";
				}
			}

			var params = "";
			var v_plugin_dom = opt.get(dom_prefix + "plugin");
			if (v_plugin_dom) {
				var v_plugin = v_plugin_dom.value;
				if (v_plugin && v_plugin != "none") {
					if (v_plugin == "simple-obfs" || v_plugin == "obfs-local") {
						v_plugin = "obfs-local";
					}
					var v_plugin_opts = opt.get(dom_prefix + "plugin_opts").value;
					if (v_plugin_opts && v_plugin_opts != "") {
						v_plugin += ";" + v_plugin_opts;
					}
					params += "&plugin=" + encodeURIComponent(v_plugin);

					if (v_plugin_dom.value == "shadow-tls" && v_plugin_opts && v_plugin_opts != "") {
						params = "shadow-tls=" + generateShadowTLSBase64(v_plugin_opts);
						shadow_tls = 1;
					}
				}
			} else if (v_type === "sing-box" || v_type === "Xray") {
				var v_transport = opt.get(dom_prefix + "transport").value;
				if (v_transport === "ws") {
					params += opt.query("host", dom_prefix + "ws_host");
					params += opt.query("path", dom_prefix + "ws_path");
					if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
						var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
						params += "?ed=" + ws_maxEarlyData;
					}
				} else if (v_transport === "h2") {
					v_transport = "http";
					params += opt.query("host", dom_prefix + "h2_host");
					params += opt.query("path", dom_prefix + "h2_path");
				} else if (v_transport === "raw" || v_transport === "tcp") {
					params += opt.query("headerType", dom_prefix + "tcp_guise");
					params += opt.query("host", dom_prefix + "tcp_guise_http_host");
					params += opt.query("path", dom_prefix + "tcp_guise_http_path");
				} else if (v_transport === "mkcp") {
					v_transport = "kcp";
					params += opt.query("headerType", dom_prefix + "mkcp_guise");
					params += opt.query("seed", dom_prefix + "mkcp_seed");
				} else if (v_transport === "quic") {
					params += opt.query("headerType", dom_prefix + "quic_guise");
					params += opt.query("key", dom_prefix + "quic_key");
					params += opt.query("quicSecurity", dom_prefix + "quic_security");
				} else if (v_transport === "grpc") {
					params += opt.query("path", dom_prefix + "grpc_serviceName");
					params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
					params += opt.query("mode", dom_prefix + "grpc_mode");
				}
				params += "&type=" + v_transport;

				if (opt.get(dom_prefix + "tls").checked) {
					var v_security = "tls";
					if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
						let v_fp = opt.get(dom_prefix + "fingerprint").value;
						params += "&fp=" + v_fp;
					}
					if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
						v_security = "reality";
						params += opt.query("pbk", dom_prefix + "reality_publicKey");
						params += opt.query("sid", dom_prefix + "reality_shortId");
						params += opt.query("spx", dom_prefix + "reality_spiderX");
						params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
					}
					params += "&security=" + v_security;
					params += opt.query("alpn", dom_prefix + "alpn");
					params += opt.query("sni", dom_prefix + "tls_serverName");
					params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
					params += opt.query("ech", dom_prefix + "ech_config");
				}

				if (opt.get(dom_prefix + "shadowtls")?.checked) {
					let st_plugin_str = "";
					let st_version = opt.get(dom_prefix + "shadowtls_version")?.value;
					if (st_version) st_plugin_str += "v" + st_version + "=1;";
					let st_password = opt.get(dom_prefix + "shadowtls_password")?.value;
					if (st_password) st_plugin_str += "passwd=" + st_password +";";
					let st_host = opt.get(dom_prefix + "shadowtls_serverName")?.value;
					if (st_host) st_plugin_str += "host=" + st_host +";";
					if (opt.get(dom_prefix + "shadowtls_utls").checked) {
						let st_fingerprint = opt.get(dom_prefix + "shadowtls_fingerprint")?.value;
						if (st_fingerprint) st_plugin_str += "fingerprint=" + st_fingerprint;
					}
					params = "shadow-tls=" + generateShadowTLSBase64(st_plugin_str);
					shadow_tls = 1;
				}
			}

			if (shadow_tls) {
				url = b64encsafe(v_method.value + ":" + v_password.value + "@" +
					_address + ":" +
					v_port.value) + "?";
			} else {
				params += "&group="
			}
			params += "#" + encodeURIComponent(v_alias.value);
			if (params[0] == "&") {
				params = params.substring(1);
			}
			url += params;
		} else if (v_type === "SSR") {
			var v_port = opt.get(dom_prefix + "port");
			var v_protocol = opt.get(dom_prefix + "protocol");
			var v_method = opt.get(dom_prefix + "method");
			var v_obfs = opt.get(dom_prefix + "obfs");
			var v_password = opt.get(dom_prefix + "password");
			var v_obfs_param = opt.get(dom_prefix + "obfs_param");
			var v_protocol_param = opt.get(dom_prefix + "protocol_param");
			var ssr_str = _address + ":" +
				v_port.value + ":" +
				v_protocol.value + ":" +
				v_method.value + ":" +
				v_obfs.value + ":" +
				b64encsafe(v_password.value) +
				"/?obfsparam=" + b64encsafe(v_obfs_param.value) +
				"&protoparam=" + b64encsafe(v_protocol_param.value) +
				"&remarks=" + b64encutf8safe(v_alias.value);
			url = b64encsafe(ssr_str);
		} else if ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vmess") {
			protocol = "vmess";
			var info = {};
			info.v = "2";
			info.ps = v_alias.value;
			info.add = opt.get(dom_prefix + "address").value;
			//info.add = _address;
			info.port = opt.get(dom_prefix + "port").value;
			info.id = opt.get(dom_prefix + "uuid").value;

			var v_transport = opt.get(dom_prefix + "transport").value;
			if (v_transport === "ws") {
				info.host = opt.get(dom_prefix + "ws_host").value;
				info.path = opt.get(dom_prefix + "ws_path").value;
				if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
					var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
					info.path = info.path + "?ed=" + ws_maxEarlyData;
				}
			} else if (v_transport === "h2") {
				info.host = opt.get(dom_prefix + "h2_host").value;
				info.path = opt.get(dom_prefix + "h2_path").value;
			} else if (v_transport === "raw" || v_transport === "tcp") {
				info.type = opt.get(dom_prefix + "tcp_guise").value;
				if (info.type === "http") {
					info.host = opt.get(dom_prefix + "tcp_guise_http_host").value;
					info.path = opt.get(dom_prefix + "tcp_guise_http_path").value;
				}
			} else if (v_transport === "mkcp") {
				v_transport = "kcp";
				info.type = opt.get(dom_prefix + "mkcp_guise").value;
				info.seed = opt.get(dom_prefix + "mkcp_seed").value;
			} else if (v_transport === "quic") {
				info.type = opt.get(dom_prefix + "quic_guise")?.value;
				info.key = opt.get(dom_prefix + "quic_key")?.value;
				info.securty = opt.get(dom_prefix + "quic_security")?.value;
			} else if (v_transport === "grpc") {
				info.path = opt.get(dom_prefix + "grpc_serviceName").value;
			}
			if (info.path && info.path != "") {
				info.path = encodeURI(info.path);
			}
			info.net = v_transport;

			info.security = opt.get(dom_prefix + "security").value || "auto";
			if (opt.get(dom_prefix + "tls").checked) {
				var v_security = "tls";
				info.tls = "tls";
				info.sni = opt.get(dom_prefix + "tls_serverName").value;
			}
			url = b64EncodeUnicode(JSON.stringify(info));
		} else if ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vless") {
			protocol = "vless";
			var v_password = opt.get(dom_prefix + "uuid");
			var v_port = opt.get(dom_prefix + "port");
			url = encodeURIComponent(v_password.value) +
				"@" + _address +
				":" + v_port.value + "?";

			var params = "";
			var v_transport = opt.get(dom_prefix + "transport").value;
			if (v_transport === "ws") {
				params += opt.query("host", dom_prefix + "ws_host");
				params += opt.query("path", dom_prefix + "ws_path");
				if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
					var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
					params += encodeURIComponent("?ed=" + ws_maxEarlyData);
				}
			} else if (v_transport === "h2") {
				v_transport = "http";
				params += opt.query("host", dom_prefix + "h2_host");
				params += opt.query("path", dom_prefix + "h2_path");
			} else if (v_transport === "raw" || v_transport === "tcp") {
				params += opt.query("headerType", dom_prefix + "tcp_guise");
				params += opt.query("host", dom_prefix + "tcp_guise_http_host");
				params += opt.query("path", dom_prefix + "tcp_guise_http_path");
			} else if (v_transport === "mkcp") {
				v_transport = "kcp";
				params += opt.query("headerType", dom_prefix + "mkcp_guise");
				params += opt.query("seed", dom_prefix + "mkcp_seed");
			} else if (v_transport === "quic") {
				params += opt.query("headerType", dom_prefix + "quic_guise");
				params += opt.query("key", dom_prefix + "quic_key");
				params += opt.query("quicSecurity", dom_prefix + "quic_security");
			} else if (v_transport === "grpc") {
				params += opt.query("path", dom_prefix + "grpc_serviceName");
				params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
				params += opt.query("mode", dom_prefix + "grpc_mode");
			} else if (v_transport === "xhttp") {
				params += opt.query("host", dom_prefix + "xhttp_host");
				params += opt.query("path", dom_prefix + "xhttp_path");
				params += opt.query("mode", dom_prefix + "xhttp_mode");
				if (opt.get(dom_prefix + "use_xhttp_extra").checked) {
					params += opt.query("extra", dom_prefix + "xhttp_extra");
				}
			} else if (v_transport === "httpupgrade") {
				v_transport = "httpupgrade";
				params += opt.query("host", dom_prefix + "httpupgrade_host");
				params += opt.query("path", dom_prefix + "httpupgrade_path");
			}
			params += "&type=" + v_transport;

			if (v_type === "sing-box") {
				params += "&encryption=none";
			} else {
				params += opt.query("encryption", dom_prefix + "encryption");
			}

			if (opt.get(dom_prefix + "tls").checked) {
				var v_security = "tls";
				if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
					let v_fp = opt.get(dom_prefix + "fingerprint").value;
					params += "&fp=" + v_fp;
				}
				if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
					v_security = "reality";
					params += opt.query("pbk", dom_prefix + "reality_publicKey");
					params += opt.query("sid", dom_prefix + "reality_shortId");
					params += opt.query("spx", dom_prefix + "reality_spiderX");
					params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
				}
				if (opt.get(dom_prefix + "flow") && opt.get(dom_prefix + "flow").value) {
					let v_flow = opt.get(dom_prefix + "flow").value;
					params += "&flow=" + v_flow;
				}
				params += "&security=" + v_security;
				params += opt.query("alpn", dom_prefix + "alpn");
				params += opt.query("sni", dom_prefix + "tls_serverName");
				params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
				params += opt.query("ech", dom_prefix + "ech_config");
			}

			params += "#" + encodeURI(v_alias.value);
			if (params[0] == "&") {
				params = params.substring(1);
			}
			url += params;
		} else if (v_type === "Trojan-Plus" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "trojan")) {
			protocol = "trojan"
			var v_password = opt.get(dom_prefix + "password");
			var v_port = opt.get(dom_prefix + "port");
			url = encodeURIComponent(v_password.value) +
				"@" + _address +
				":" + v_port.value + "/?";
			var params = "";
			var v_transport = opt.get(dom_prefix + "transport").value;
			if (v_transport === "ws") {
				params += opt.query("host", dom_prefix + "ws_host");
				params += opt.query("path", dom_prefix + "ws_path");
				if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
					var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
					params += "?ed=" + ws_maxEarlyData;
				}
			} else if (v_transport === "h2") {
				v_transport = "http";
				params += opt.query("host", dom_prefix + "h2_host");
				params += opt.query("path", dom_prefix + "h2_path");
			} else if (v_transport === "raw" || v_transport === "tcp") {
				params += opt.query("headerType", dom_prefix + "tcp_guise");
				params += opt.query("host", dom_prefix + "tcp_guise_http_host");
				params += opt.query("path", dom_prefix + "tcp_guise_http_path");
			} else if (v_transport === "mkcp") {
				v_transport = "kcp";
				params += opt.query("headerType", dom_prefix + "mkcp_guise");
				params += opt.query("seed", dom_prefix + "mkcp_seed");
			} else if (v_transport === "quic") {
				params += opt.query("headerType", dom_prefix + "quic_guise");
				params += opt.query("key", dom_prefix + "quic_key");
				params += opt.query("quicSecurity", dom_prefix + "quic_security");
			} else if (v_transport === "grpc") {
				params += opt.query("path", dom_prefix + "grpc_serviceName");
				params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
				params += opt.query("mode", dom_prefix + "grpc_mode");
			}
			params += "&type=" + v_transport;

			if (opt.get(dom_prefix + "tls").checked) {
				var v_security = "tls";
				if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
					let v_fp = opt.get(dom_prefix + "fingerprint").value;
					params += "&fp=" + v_fp;
				}
				if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
					v_security = "reality";
					params += opt.query("pbk", dom_prefix + "reality_publicKey");
					params += opt.query("sid", dom_prefix + "reality_shortId");
					params += opt.query("spx", dom_prefix + "reality_spiderX");
					params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
				}
				params += "&security=" + v_security;
				params += opt.query("alpn", dom_prefix + "alpn");
				params += opt.query("sni", dom_prefix + "tls_serverName");
				params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
				params += opt.query("ech", dom_prefix + "ech_config");
			}
			params += "#" + encodeURI(v_alias.value);
			if (params[0] == "&") {
				params = params.substring(1);
			}
			url += params;
		} else if ((v_type === "Hysteria2") || (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "hysteria2")) {
			protocol = "hysteria2"
			var v_port = opt.get(dom_prefix + "port");
			var params = "";
			params += opt.query("sni", dom_prefix + "tls_serverName");
			params += opt.query("insecure", dom_prefix + "tls_allowInsecure");
			
			var v_password = null;
			
			if (v_type === "Hysteria2") {
				v_password = opt.get("hysteria2_auth_password");
				params += opt.query("pinSHA256", "hysteria2_tls_pinSHA256");
				var dom_obfs = opt.get("hysteria2_obfs");
				if (dom_obfs && dom_obfs.value != "") {
					params += "&obfs=" + "salamander";
					params += opt.query("obfs-password", "hysteria2_obfs");
				}
				params += opt.query("mport", "hysteria2_hop");
			} else {
				v_password = opt.get(dom_prefix + "hysteria2_auth_password");
				var dom_obfs_type = opt.get(dom_prefix + "hysteria2_obfs_type");
				if (dom_obfs_type && dom_obfs_type.value != "") {
					params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type");
					params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password");
				}
				params += opt.query("mport", dom_prefix + "hysteria2_hop");
			}
			params = params.replace(/^&/, "");
			url =
				_address + ":" +
				v_port.value + "?" +
				params +
				"#" + encodeURI(v_alias.value);
			if (v_password) {
				url = encodeURIComponent(v_password.value) + "@" + url
			}
		} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "tuic") {
			protocol = "tuic";
			var v_username = opt.get(dom_prefix + "uuid");
			var v_password = opt.get(dom_prefix + "password");
			var v_port = opt.get(dom_prefix + "port");
			url = encodeURIComponent(v_username.value) +
				":" + encodeURIComponent(v_password.value) +
				"@" + _address +
				":" + v_port.value + "?";

			var params = "";
			params += opt.query("sni", dom_prefix + "tls_serverName");
			params += opt.query("alpn", dom_prefix + "tuic_alpn");
			params += opt.query("congestion_control", dom_prefix + "tuic_congestion_control");
			params += opt.query("udp_relay_mode", dom_prefix + "tuic_udp_relay_mode");
			params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");

			params += "#" + encodeURI(v_alias.value);
			if (params[0] == "&") {
				params = params.substring(1);
			}
			url += params;
		} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "anytls") {
			protocol = "anytls";
			var v_password = opt.get(dom_prefix + "password");
			var v_port = opt.get(dom_prefix + "port");
			url = encodeURIComponent(v_password.value) +
				"@" + _address +
				":" + v_port.value + "?";

			var params = "";
			if (opt.get(dom_prefix + "tls").checked) {
				var v_security = "tls";
				if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
					let v_fp = opt.get(dom_prefix + "fingerprint").value;
					params += "&fp=" + v_fp;
				}
				if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
					v_security = "reality";
					params += opt.query("pbk", dom_prefix + "reality_publicKey");
					params += opt.query("sid", dom_prefix + "reality_shortId");
				}
				params += "&security=" + v_security;
				params += opt.query("alpn", dom_prefix + "alpn");
				params += opt.query("sni", dom_prefix + "tls_serverName");
				params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
			}

			params += "#" + encodeURI(v_alias.value);
			if (params[0] == "&") {
				params = params.substring(1);
			}
			url += params;
		}
		if (url) {
			url = protocol.toLowerCase() + "://" + url;
			return url;
		} else {
			alert("<%:Not a supported scheme:%> " + v_type);
		}
		return false;
	}

	function exportUrl(btn, urlname, sid) {
		var url = buildUrl(btn, urlname, sid);
		if (url) {
			var textarea = document.createElement("textarea");
			textarea.textContent = url;
			textarea.style.position = "fixed";
			document.body.appendChild(textarea);
			textarea.select();
			try {
				var s = document.getElementById(urlname + "-status");
				if (!s) {
					alert("Never");
					return false;
				}
				document.execCommand("copy"); // Security exception may be thrown by some browsers.
				s.innerHTML = "<font color='green'><%:Share URL to clipboard successfully.%></font>";
			} catch (ex) {
				s.innerHTML = "<font color='red'><%:Share URL to clipboard unable.%></font>";
			} finally {
				document.body.removeChild(textarea);
			}
		}
	}

	function unbracketIP(server) {
		if (!server) return '';
		return server.replace(/^\[/, '').replace(/\]$/, '');
	}

	function fromUrl(btn, urlname, sid) {
		var opt = {
			base: 'cbid.passwall',
			client: true,
			get: function (opt) {
				var obj;
				var id = this.base + '.' + opt;
				obj = document.getElementsByName(id)[0] || document.getElementById(id);
				if (obj) {
					var combobox = document.getElementById('cbi.combobox.' + id);
					if (combobox) {
						obj.combobox = combobox;
					}
					var div = document.getElementById(id);
					if (div && div.getElementsByTagName("li").length > 0) {
						obj = div;
					}
					return obj;
				} else {
					return null;
				}
			},
			set: function (opt, val) {
				var obj;
				obj = this.get(opt);
				if (obj) {
					var event = document.createEvent("HTMLEvents");
					event.initEvent("change", true, true);
					if (obj.type === 'checkbox') {
						obj.checked = val;
					} else {
						obj.value = val;
						if (obj.combobox) {
							obj.combobox.value = val;
						}

						var list = obj.getElementsByTagName("li");
						if (list.length > 0) {
							for (var i = 0; i < list.length; i++) {
								var li = list[i];
								var data = li.getAttribute("data-value");
								li.removeAttribute("selected");
								li.removeAttribute("display");
								if (data && data == val) {
									li.setAttribute("selected", true);
									li.setAttribute("display", "0");
								}
							}
							var input = document.getElementsByName(obj.id)[0];
							if (input) {
								input.value = val;
							} else {
								var input = document.createElement("input");
								input.setAttribute("type", "hidden");
								input.setAttribute("name", obj.id);
								input.setAttribute("value", val);
								obj.appendChild(input);
							}
						}
					}
					try {
						obj.dispatchEvent(event);
					} catch (err) {}
				} else {
					//alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val);
					// 处理 DynamicList
					var fullName = this.base + '.' + opt;
					var lists = document.querySelectorAll('.cbi-dynlist');
					for (var i = 0; i < lists.length; i++) {
						var parent = lists[i].closest('.cbi-value');
						if (!parent) continue;
						// 尝试从 label 的 for 属性中提取 fullName
						var label = parent.querySelector('label.cbi-value-title');
						var labelFor = label?.getAttribute('for');
						if (labelFor === fullName) {
							var input = lists[i].querySelector('input[type="text"]');
							var addBtn = lists[i].querySelector('.cbi-button-add');
							if (input && addBtn) {
								input.value = val;
								addBtn.click();
							}
							break;
						}
					}
				}
			},
			setlist: function (opt, vlist) {
				var id = this.base + "." + opt;
				var objs = document.getElementsByName(id) || document.getElementsByClassName(id);
				if (objs) {
					var values = "";
					for (var i = 0; i < vlist.length; i++) {
						values += vlist[i] + ", ";
					}
					alert("Manually input the option:\n" + opt + "s:\n[" + values + "]");
				} else {
					//alert("<%:Faltal on set option, please help in debug: %>" + opt);
				}
			}
		}

		var s = document.getElementById(urlname + '-status');
		if (!s) {
			alert("Never");
			return false;
		}
		opt.base = "cbid." + urlname + "." + sid;
		opt.client = urlname.indexOf("server") === -1;
		var ssrurl = prompt('<%:Paste Share URL Here%>', '');
		if (ssrurl === null || ssrurl === "") {
			return false;
		}
		ssrurl = ssrurl.replace(/&amp;/gi, '&').replace(/\s*#\s*/, '#').trim();  //一些奇葩的链接用"&amp;"当做"&"，"#"前后带空格
		s.innerHTML = "";
		var ssu = ssrurl.split('://');
		var event = document.createEvent("HTMLEvents");
		event.initEvent("change", true, true);

		var dom_prefix = null

		if (ssu[0] === "ssr") {
			dom_prefix = "ssr_"
			//var b64c = ssu[1].match(/([A-Za-z0-9_-]+)/);
			var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
			var ploc = sstr.indexOf("/?");
			var url0 = "", param = "";
			if (ploc > 0) {
				url0 = sstr.substr(0, ploc);
				param = sstr.substr(ploc + 2);
			} else {
				var url0 = sstr;
			}
			var ssm = url0.match(/^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)/);
			if (!ssm || ssm.length < 7) {
				s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
				return false;
			}
			var pdict = {};
			if (param.length > 2) {
				var a = param.split('&');
				for (var i = 0; i < a.length; i++) {
					var b = a[i].split('=');
					pdict[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
				}
			}
			opt.set('type', "SSR");
			opt.set(dom_prefix + 'address', unbracketIP(ssm[1]));
			opt.set(dom_prefix + 'port', ssm[2]);
			opt.set(dom_prefix + 'protocol', ssm[3]);
			opt.set(dom_prefix + 'method', ssm[4]);
			opt.set(dom_prefix + 'obfs', ssm[5]);
			opt.set(dom_prefix + 'password', b64decsafe(ssm[6]));
			opt.set(dom_prefix + 'obfs_param', dictvalue(pdict, 'obfsparam'));
			opt.set(dom_prefix + 'protocol_param', dictvalue(pdict, 'protoparam'));
			var rem = pdict['remarks'];
			if (typeof (rem) !== 'undefined' && rem !== '' && rem.length > 0)
				opt.set('remarks', b64decutf8safe(rem));
		}
		if (ssu[0] === "ss") {
			var url0 = ssu[1] || "";
			param = "";

			var ploc = url0.indexOf("#");
			if (ploc >= 0) {
				param = url0.substr(ploc + 1);
				url0 = url0.substr(0, ploc);
			}

			var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
			var queryStr = "";
			if (queryIndex >= 0) {
				queryStr = url0.substr(queryIndex + 1);
				url0 = url0.substr(0, queryIndex);
			}
			var queryParam = {};
			queryParam = Object.fromEntries(new URLSearchParams(queryStr));

			var server, port, method, password, plugin, pluginOpts;
			var sipIndex = url0.indexOf("@");
			if (sipIndex !== -1) {
				// SIP002 base64(method:pass)@host:port
				var userInfo = b64decsafe(decodeURIComponent(url0.substr(0, sipIndex)));
				var temp = url0.substr(sipIndex + 1);
				var serverInfo = temp.split(":");
				server = serverInfo[0];
				port = serverInfo[1];
				var userInfoSplitIndex = userInfo.indexOf(":");
				if (userInfoSplitIndex !== -1) {
					method = userInfo.substr(0, userInfoSplitIndex);
					password = userInfo.substr(userInfoSplitIndex + 1);
				} else {
					password = url0.substr(0, sipIndex);  //一些链接用明文uuid做密码
				}
			} else {
				// base64(method:pass@host:port)
				var sstr = b64decsafe(decodeURIComponent(url0));
				var m2022 = sstr.match(/^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/);
				var mNormal = sstr.match(/^([^:]+):([^@]+)@([^:]+):(\d+)$/);
				if (m2022) {
					method = m2022[1];
					password = m2022[2] + ":" + m2022[3];
					server = m2022[4];
					port = m2022[5];
				} else if (mNormal) {
					method = mNormal[1];
					password = mNormal[2];
					server = mNormal[3];
					port = mNormal[4];
				}
			}

			// 判断密码是否经过url编码
			const isURLEncodedPassword = function(pwd) {
				if (!/%[0-9A-Fa-f]{2}/.test(pwd)) return false;
				try {
					const decoded = decodeURIComponent(pwd.replace(/\+/g, "%20"));
					const reencoded = encodeURIComponent(decoded);
					return reencoded === pwd;
				} catch (e) {
					return false;
				}
			}
			password = isURLEncodedPassword(password) ? decodeURIComponent(password) : password;

			if (queryParam.plugin) {
				var pluginParams = decodeURIComponent(queryParam.plugin).split(";");
				plugin = pluginParams.shift();
				pluginOpts = pluginParams.join(";");
			}

			if (has_xray && ((ss_type !== "xray" && ss_type !== "sing-box" && queryParam.type) || ss_type == "xray")) {
				dom_prefix = "xray_"
				opt.set('type', "Xray");
				opt.set(dom_prefix + 'protocol', "shadowsocks");
			} else if (has_singbox && ((ss_type !== "xray" && ss_type !== "sing-box" && queryParam.type) || ss_type == "sing-box")) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
				opt.set(dom_prefix + 'protocol', "shadowsocks");
			} else if (ss_type == "shadowsocks-rust") {
				dom_prefix = "ssrust_"
				opt.set('type', "SS-Rust");
			} else {
				if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) {
					dom_prefix = "ssrust_"
					opt.set('type', "SS-Rust");
				} else {
					dom_prefix = "ss_"
					opt.set('type', "SS");
				}
			}

			const _method = (method || "none").toLowerCase();
			const mapping = {
				"chacha20-poly1305": "chacha20-ietf-poly1305",
				"xchacha20-poly1305": "xchacha20-ietf-poly1305",
			};
			method = mapping[_method] || _method;

			opt.set(dom_prefix + 'address', unbracketIP(server));
			opt.set(dom_prefix + 'port', port);
			opt.set(dom_prefix + 'password', password || "");
			opt.set(dom_prefix + 'method', method || "");
			opt.set(dom_prefix + 'ss_method', method || "");
			if (plugin && plugin != "none") {
				plugin = (plugin === "simple-obfs") ? "obfs-local" : plugin;
				opt.set(dom_prefix + 'plugin_enabled', true);
				opt.set(dom_prefix + 'plugin', plugin || "none");
				opt.set(dom_prefix + 'plugin_opts', pluginOpts || "");
				//obfs-local插件转换成xray支持的格式
				if (plugin == "obfs-local" && dom_prefix == "xray_") {
					var obfs = pluginOpts.match(/obfs=([^;]+)/);
					var obfs_host = pluginOpts.match(/obfs-host=([^;]+)/);
					obfs = obfs ? obfs[1] : "";
					obfs_host = obfs_host ? obfs_host[1] : "";
					if (obfs === "http") {
						opt.set(dom_prefix + 'transport', "raw");
						opt.set(dom_prefix + 'tcp_guise', "http");
						opt.set(dom_prefix + 'tcp_guise_http_host', obfs_host || '');
						opt.set(dom_prefix + 'tcp_guise_http_path', '/');
					} else if (obfs === "tls") {
						opt.set(dom_prefix + 'tls', true);
						opt.set(dom_prefix + 'tls_serverName', obfs_host || '');
						opt.set(dom_prefix + 'tls_allowInsecure', true);
					}
				}
			} else {
				opt.set(dom_prefix + 'plugin', "none");
			}
			if (param !== undefined) {
				opt.set('remarks', decodeURIComponent(param));
			}

			if (Object.keys(queryParam).length > 0 && !queryParam.plugin) {
				if (queryParam.security) {
					if (queryParam.security == "tls") {
						opt.set(dom_prefix + 'tls', true);
						opt.set(dom_prefix + 'reality', false);
						opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
						opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
						opt.set(dom_prefix + 'tls_allowInsecure', true);
						if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
							opt.set(dom_prefix + 'tls_allowInsecure', false);
						}
						if (queryParam.fp && queryParam.fp.trim() != "") {
							opt.set(dom_prefix + 'utls', true);
							opt.set(dom_prefix + 'fingerprint', queryParam.fp);
						}
						opt.set(dom_prefix + 'ech', !!queryParam.ech);
						opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
					}

					if (queryParam.security == "reality") {
						opt.set(dom_prefix + 'tls', true);
						opt.set(dom_prefix + 'reality', true);
						opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
						opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
						if (queryParam.fp && queryParam.fp.trim() != "") {
							opt.set(dom_prefix + 'utls', true);
							opt.set(dom_prefix + 'fingerprint', queryParam.fp);
						}
						opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
						opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
						opt.set(dom_prefix + 'reality_spiderX', queryParam.spx || '');
						opt.set(dom_prefix + 'use_mldsa65Verify', !!queryParam.pqv);
						opt.set(dom_prefix + 'reality_mldsa65Verify', queryParam.pqv || '');
					}
				}

				queryParam.type = queryParam.type?.toLowerCase();
				if (queryParam.type === "kcp") {
					queryParam.type = "mkcp";
				}
				if (queryParam.type === "h2") {
					queryParam.type = "http";
				}
				if (dom_prefix == "singbox_" && queryParam.type === "raw") {
					queryParam.type = "tcp";
				} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
					queryParam.type = "raw";
				}
				if (dom_prefix == "xray_" && queryParam.type === "http") {
					opt.set(dom_prefix + 'transport', "xhttp");
				} else {
					opt.set(dom_prefix + 'transport', queryParam.type);
				}
				if (queryParam.type === "raw" || queryParam.type === "tcp") {
					opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
					if (queryParam.headerType && queryParam.headerType != "none") {
						opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
						opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
					}
				} else if (queryParam.type === "ws") {
					opt.set(dom_prefix + 'ws_host', queryParam.host || "");
					opt.set(dom_prefix + 'ws_path', queryParam.path || "");
					if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
						var ws_path_params = {};
						var ws_path_dat = queryParam.path.split('?');
						var ws_path = ws_path_dat[0];
						var ws_path_params = {};
						var ws_path_params_array = (ws_path_dat[1] || '').split('&');
						for (i = 0; i < ws_path_params_array.length; i++) {
							var kv = ws_path_params_array[i].split('=');
							ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
						}
						
						if (ws_path_params.ed) {
							opt.set(dom_prefix + 'ws_path', ws_path);
							opt.set(dom_prefix + 'ws_enableEarlyData', true);
							opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
							opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
						}
					}
				} else if (queryParam.type === "http") {
					if (dom_prefix == "xray_") {
						opt.set(dom_prefix + 'xhttp_mode', "stream-one");
						opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
						opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
					} else {
						opt.set(dom_prefix + 'http_host', queryParam.host || "");
						opt.set(dom_prefix + 'http_path', queryParam.path || "");
					}
				} else if (queryParam.type === "quic") {
					opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
					opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
					opt.set(dom_prefix + 'quic_key', queryParam.key);
				} else if (queryParam.type === "mkcp") {
					opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
					opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
				} else if (queryParam.type === "grpc") {
					opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
					opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
				}
			
				if (queryParam["shadow-tls"]) {
					//解析SS Shadow-TLS 插件参数
					const parseShadowTLSParams = function(base64Str, outObj) {
						try {
							let obj = JSON.parse(b64decsafe(base64Str));
							if (outObj && typeof outObj === "object") {
								for (let k in obj) outObj[k] = obj[k];
							}
							let out = [];
							if (obj.version) out.push("v" + obj.version + "=1");
							if (obj.password) out.push("passwd=" + obj.password);
							for (let k in obj)
								if (k !== "version" && k !== "password")
									out.push(k + "=" + obj[k]);
							return out.join(";");
						} catch (e) {
							return "";
						}
					}
					if (dom_prefix === "ssrust_") {
						opt.set(dom_prefix + 'plugin_enabled', true);
						opt.set(dom_prefix + 'plugin', "shadow-tls");
						let shadowtlsOpt = parseShadowTLSParams(queryParam["shadow-tls"]);
						opt.set(dom_prefix + 'plugin_opts', shadowtlsOpt || "");
					} else if (dom_prefix === "singbox_") {
						let shadowtlsOpt = {};
						parseShadowTLSParams(queryParam["shadow-tls"], shadowtlsOpt);
						if (Object.keys(shadowtlsOpt).length > 0) {
							opt.set(dom_prefix + 'shadowtls', true);
							opt.set(dom_prefix + 'shadowtls_version', shadowtlsOpt.version || "1");
							opt.set(dom_prefix + 'shadowtls_password', shadowtlsOpt.password || "");
							opt.set(dom_prefix + 'shadowtls_serverName', shadowtlsOpt.host || "");
							if (shadowtlsOpt.fingerprint) {
								opt.set(dom_prefix + 'shadowtls_utls', true);
								opt.set(dom_prefix + 'shadowtls_fingerprint', shadowtlsOpt.fingerprint || "chrome");
							}
						}
					}
				}
			}
		}
		if (ssu[0] === "trojan" || ssu[0] === "trojan-plus") {
			if (trojan_type == "sing-box" && has_singbox) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
				opt.set(dom_prefix + 'protocol', "trojan");
			} else if (trojan_type == "xray" && has_xray) {
				dom_prefix = "xray_"
				opt.set('type', "Xray");
				opt.set(dom_prefix + 'protocol', "trojan");
			} else {
				dom_prefix = "trojan_plus_"
				opt.set('type', "Trojan-Plus");
			}
			var m = parseNodeUrl(ssrurl);
			var password = m.passwd;
			if (password === "") {
				s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
				return false;
			}
			var queryParam = {};
			if (m.search.length > 1) {
				var query = m.search.replace('/?', '?').split('?');
				var queryParams = query[1];
				var queryArray = queryParams.split('&');
				var params;
				for (var i = 0; i < queryArray.length; i++) {
					params = queryArray[i].split('=');
					queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
				}
			}
			opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
			opt.set(dom_prefix + 'port', m.port || "443");
			opt.set(dom_prefix + 'password', decodeURIComponent(password));

			queryParam.type = queryParam.type ? queryParam.type.toLowerCase() : "tcp";
			if (queryParam.type === "kcp") {
				queryParam.type = "mkcp";
			}
			if (queryParam.type === "h2") {
				queryParam.type = "http";
			}
			if (dom_prefix == "singbox_" && queryParam.type === "raw") {
				queryParam.type = "tcp";
			} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
				queryParam.type = "raw";
			}
			if (dom_prefix == "xray_" && queryParam.type === "http") {
				opt.set(dom_prefix + 'transport', "xhttp");
			} else {
				opt.set(dom_prefix + 'transport', queryParam.type);
			}
			if (queryParam.type === "raw" || queryParam.type === "tcp") {
				opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
				if (queryParam.headerType && queryParam.headerType != "none") {
					opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
					opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
				}
			} else if (queryParam.type === "ws") {
				opt.set(dom_prefix + 'ws_host', queryParam.host || "");
				opt.set(dom_prefix + 'ws_path', queryParam.path || "");
				if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
					var ws_path_params = {};
					var ws_path_dat = queryParam.path.split('?');
					var ws_path = ws_path_dat[0];
					var ws_path_params = {};
					var ws_path_params_array = (ws_path_dat[1] || '').split('&');
					for (i = 0; i < ws_path_params_array.length; i++) {
						var kv = ws_path_params_array[i].split('=');
						ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
					}
					
					if (ws_path_params.ed) {
						opt.set(dom_prefix + 'ws_path', ws_path);
						opt.set(dom_prefix + 'ws_enableEarlyData', true);
						opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
						opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
					}
				}
			} else if (queryParam.type === "http") {
				if (dom_prefix == "xray_") {
					opt.set(dom_prefix + 'xhttp_mode', "stream-one");
					opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
					opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
				} else {
					opt.set(dom_prefix + 'http_host', queryParam.host || "");
					opt.set(dom_prefix + 'http_path', queryParam.path || "");
				}
			} else if (queryParam.type === "quic") {
				opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
				opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
				opt.set(dom_prefix + 'quic_key', queryParam.key);
			} else if (queryParam.type === "mkcp") {
				opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
				opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
			} else if (queryParam.type === "grpc") {
				opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
				opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
			}

			queryParam.security = queryParam.security || "tls";
			opt.set(dom_prefix + 'tls', queryParam.security === "tls");
			if (queryParam.security === "tls") {
				var tls_serverName = queryParam.peer;
				if (queryParam.sni) {
					tls_serverName = queryParam.sni
				}
				tls_serverName = tls_serverName || "";
				opt.set(dom_prefix + 'tls_serverName', tls_serverName);
				opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
			}
			opt.set(dom_prefix + 'tls_allowInsecure', true);
			if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
				opt.set(dom_prefix + 'tls_allowInsecure', false);
			}

			if (m.hash) {
				opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
			}
		}
		if (ssu[0] === "vmess") {
			var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
			var ploc = sstr.indexOf("/?");
			if (vmess_type == "sing-box" && has_singbox) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
			} else if (has_xray) {
				dom_prefix = "xray_"
				opt.set('type', "Xray");
			}
			opt.set(dom_prefix + 'protocol', "vmess");
			var url0, param = "";
			if (ploc > 0) {
				url0 = sstr.substr(0, ploc);
				param = sstr.substr(ploc + 2);
			}
			var ssm = JSON.parse(sstr);
			opt.set('remarks', ssm.ps);
			opt.set(dom_prefix + 'address', unbracketIP(ssm.add));
			opt.set(dom_prefix + 'port', ssm.port);
			opt.set(dom_prefix + 'uuid', ssm.id);
			opt.set(dom_prefix + 'tls', ssm.tls === "tls");
			if (ssm.tls === "tls") {
				var tls_serverName = ssm.host;
				if (ssm.sni) {
					tls_serverName = ssm.sni
				}
				opt.set(dom_prefix + 'tls_serverName', tls_serverName);
			}
			ssm.net = ssm.net.toLowerCase();
			if (ssm.net === "kcp" || ssm.net === "mkcp")
				ssm.net = "mkcp"
			if (dom_prefix == "singbox_" && ssm.net === "raw") {
				ssm.net = "tcp";
			} else if (dom_prefix == "xray_" && ssm.net === "tcp") {
				ssm.net = "raw";
			}
			if (ssm.net === "h2" || ssm.net === "http") {
				ssm.net = "http";
			}
			if (dom_prefix == "xray_" && ssm.net === "http") {
				opt.set(dom_prefix + 'transport', "xhttp");
			} else {
				opt.set(dom_prefix + 'transport', ssm.net);
			}
			if (ssm.net === "raw" || ssm.net === "tcp") {
				opt.set(dom_prefix + 'tcp_guise', (ssm.host && ssm.host != "") ? "http" : "none");
				if (ssm.host && ssm.host != "") {
					opt.set(dom_prefix + 'tcp_guise_http_host', ssm.host);
					opt.set(dom_prefix + 'tcp_guise_http_path', ssm.path || "");
				}
			} else if (ssm.net === "ws") {
				opt.set(dom_prefix + 'ws_host', ssm.host);
				opt.set(dom_prefix + 'ws_path', ssm.path);
				if (dom_prefix == "singbox_" && ssm.path && ssm.path.length > 1) {
					var ws_path_params = {};
					var ws_path_dat = ssm.path.split('?');
					var ws_path = ws_path_dat[0];
					var ws_path_params = {};
					var ws_path_params_array = (ws_path_dat[1] || '').split('&');
					for (i = 0; i < ws_path_params_array.length; i++) {
						var kv = ws_path_params_array[i].split('=');
						ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
					}
					
					if (ws_path_params.ed) {
						opt.set(dom_prefix + 'ws_path', ws_path);
						opt.set(dom_prefix + 'ws_enableEarlyData', true);
						opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
						opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
					}
				}
			} else if (ssm.net === "http") {
				if (dom_prefix == "xray_") {
					opt.set(dom_prefix + 'xhttp_mode', "stream-one");
					opt.set(dom_prefix + 'xhttp_host', ssm.host || "");
					opt.set(dom_prefix + 'xhttp_path', ssm.path || "");
				} else {
					opt.set(dom_prefix + 'http_host', ssm.host || "");
					opt.set(dom_prefix + 'http_path', ssm.path || "");
				}
			} else if (ssm.net === "quic") {
				opt.set(dom_prefix + 'quic_security', ssm.securty);
				opt.set(dom_prefix + 'quic_key', ssm.key);
			} else if (ssm.net === "kcp" || ssm.net === "mkcp") {
				opt.set(dom_prefix + 'mkcp_guise', ssm.type || "none");
				opt.set(dom_prefix + 'mkcp_seed', ssm.seed || "");
			} else if (ssm.net === "grpc") {
				opt.set(dom_prefix + 'grpc_serviceName', ssm.path);
			}
		}
		if (ssu[0] === "vless") {
			if (vless_type == "sing-box" && has_singbox) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
			} else if (has_xray) {
				dom_prefix = "xray_"
				opt.set('type', "Xray");
			}
			
			var m = parseNodeUrl(ssrurl);
			var password = m.passwd;
			if (password === "") {
				s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
				return false;
			}
			var queryParam = {};
			if (m.search.length > 1) {
				var query = m.search.replace('/?', '?').split('?')
				var queryParams = query[1];
				var queryArray = queryParams.split('&');
				var params;
				for (i = 0; i < queryArray.length; i++) {
					params = queryArray[i].split('=');
					queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
				}
			}

			queryParam.type = queryParam.type.toLowerCase();
			if (["xhttp", "kcp", "mkcp"].includes(queryParam.type) && vless_type !== "xray" && has_xray) {
				dom_prefix = "xray_"
				opt.set('type', "Xray");
			}
			opt.set(dom_prefix + 'protocol', "vless");
			opt.set(dom_prefix + 'uuid', password);
			opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
			opt.set(dom_prefix + 'port', m.port || "443");

			opt.set(dom_prefix + 'encryption', queryParam.encryption || "none");
			opt.set(dom_prefix + 'flow', (queryParam.flow || '').replace('-udp443', ''));
			if (queryParam.security) {
				if (queryParam.security == "tls") {
					opt.set(dom_prefix + 'tls', true);
					opt.set(dom_prefix + 'reality', false);
					opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
					opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
					opt.set(dom_prefix + 'tls_allowInsecure', true);
					if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
						opt.set(dom_prefix + 'tls_allowInsecure', false);
					}
					if (queryParam.fp && queryParam.fp.trim() != "") {
						opt.set(dom_prefix + 'utls', true);
						opt.set(dom_prefix + 'fingerprint', queryParam.fp);
					}
					opt.set(dom_prefix + 'ech', !!queryParam.ech);
					opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
				}

				if (queryParam.security == "reality") {
					opt.set(dom_prefix + 'tls', true);
					opt.set(dom_prefix + 'reality', true);
					opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
					opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
					if (queryParam.fp && queryParam.fp.trim() != "") {
						opt.set(dom_prefix + 'utls', true);
						opt.set(dom_prefix + 'fingerprint', queryParam.fp);
					}
					opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
					opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
					opt.set(dom_prefix + 'reality_spiderX', queryParam.spx || '');
					opt.set(dom_prefix + 'use_mldsa65Verify', !!queryParam.pqv);
					opt.set(dom_prefix + 'reality_mldsa65Verify', queryParam.pqv || '');
				}

			}

			if (queryParam.type === "kcp") {
				queryParam.type = "mkcp";
			}
			if (queryParam.type === "h2") {
				queryParam.type = "http";
			}
			if (dom_prefix == "singbox_" && queryParam.type === "raw") {
				queryParam.type = "tcp";
			} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
				queryParam.type = "raw";
			}
			if (dom_prefix == "xray_" && queryParam.type === "http") {
				opt.set(dom_prefix + 'transport', "xhttp");
			} else {
				opt.set(dom_prefix + 'transport', queryParam.type);
			}
			if (queryParam.type === "raw" || queryParam.type === "tcp") {
				opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
				if (queryParam.headerType && queryParam.headerType != "none") {
					opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
					opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
				}
			} else if (queryParam.type === "ws") {
				opt.set(dom_prefix + 'ws_host', queryParam.host || "");
				opt.set(dom_prefix + 'ws_path', queryParam.path || "");
				if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
					var ws_path_params = {};
					var ws_path_dat = queryParam.path.split('?');
					var ws_path = ws_path_dat[0];
					var ws_path_params = {};
					var ws_path_params_array = (ws_path_dat[1] || '').split('&');
					for (i = 0; i < ws_path_params_array.length; i++) {
						var kv = ws_path_params_array[i].split('=');
						ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
					}
					
					if (ws_path_params.ed) {
						opt.set(dom_prefix + 'ws_path', ws_path);
						opt.set(dom_prefix + 'ws_enableEarlyData', true);
						opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
						opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
					}
				}
			} else if (queryParam.type === "h2" || queryParam.type === "http") {
				if (dom_prefix == "xray_") {
					opt.set(dom_prefix + 'xhttp_mode', "stream-one");
					opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
					opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
				} else {
					opt.set(dom_prefix + 'http_host', queryParam.host || "");
					opt.set(dom_prefix + 'http_path', queryParam.path || "");
				}
			} else if (queryParam.type === "quic") {
				opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
				opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
				opt.set(dom_prefix + 'quic_key', queryParam.key);
			} else if (queryParam.type === "kcp" || queryParam.type === "mkcp") {
				opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
				opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
			} else if (queryParam.type === "grpc") {
				opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
				opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
			} else if (queryParam.type === "xhttp") {
				opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
				opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
				opt.set(dom_prefix + 'xhttp_mode', queryParam.mode || "auto");
				opt.set(dom_prefix + 'use_xhttp_extra', !!queryParam.extra);
				opt.set(dom_prefix + 'xhttp_extra', queryParam.extra || "");
			} else if (queryParam.type === "httpupgrade") {
				opt.set(dom_prefix + 'httpupgrade_host', queryParam.host || "");
				opt.set(dom_prefix + 'httpupgrade_path', queryParam.path || "");
			}

			if (m.hash) {
				opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
			}
		}
		if (ssu[0] === "hysteria2" || ssu[0] === "hy2") {
			var m = parseNodeUrl(ssrurl);
			var password = m.passwd;
			if (password === "") {
				s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
				return false;
			}
			var queryParam = {};
			if (m.search.length > 1) {
				var query = m.search.replace('/?', '?').split('?')
				var queryParams = query[1];
				var queryArray = queryParams.split('&');
				var params;
				for (i = 0; i < queryArray.length; i++) {
					params = queryArray[i].split('=');
					queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
				}
			}
			if (hysteria2_type == "sing-box" && has_singbox) {
				opt.set('type', "sing-box");
				dom_prefix = "singbox_"
				opt.set(dom_prefix + 'protocol', "hysteria2");
				opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password));
				if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
					opt.set(dom_prefix + 'hysteria2_obfs_type', "salamander");
					opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
				}
				opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || "");
			} else if (has_hysteria2) {
				opt.set('type', "Hysteria2");
				dom_prefix = "hysteria2_"
				opt.set(dom_prefix + 'auth_password', decodeURIComponent(password));
				if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
					opt.set(dom_prefix + 'obfs', queryParam["obfs-password"] || queryParam["obfs_password"]);
				}
				if (queryParam.pinSHA256) {
					opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pinSHA256);
				}
				opt.set(dom_prefix + 'hop', queryParam.mport || "");
			}
			
			opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
			opt.set(dom_prefix + 'port', m.port || "443");
			
			opt.set(dom_prefix + 'tls_serverName', queryParam.sni || "");
			if (queryParam.insecure && queryParam.insecure == "1") {
				opt.set(dom_prefix + 'tls_allowInsecure', true);
			}
			if (m.hash) {
				opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
			}
		}
		if (ssu[0] === "tuic") {
			if (has_singbox) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
			}
			opt.set(dom_prefix + 'protocol', "tuic");
			var _parsedUrl = new URL("http://" + ssu[1]);
			var username = _parsedUrl.username;
			var password = _parsedUrl.password;
			var hostname = _parsedUrl.hostname;
			var port = _parsedUrl.port;
			var search = _parsedUrl.search;
			var hash = _parsedUrl.hash;
			opt.set(dom_prefix + 'uuid', decodeURIComponent(username));
			opt.set(dom_prefix + 'password', decodeURIComponent(password));
			opt.set(dom_prefix + 'address', unbracketIP(hostname));
			opt.set(dom_prefix + 'port', port || "443");
			var queryParam = {};
			if (search.length > 1) {
				var query = search.split('?')
				var queryParams = query[1];
				var queryArray = queryParams.split('&');
				var params;
				for (i = 0; i < queryArray.length; i++) {
					params = queryArray[i].split('=');
					queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
				}
			}
			opt.set(dom_prefix + 'tuic_congestion_control', queryParam.congestion_control || 'cubic');
			opt.set(dom_prefix + 'tuic_udp_relay_mode', queryParam.udp_relay_mode || 'native');
			opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'default');
			opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
			opt.set(dom_prefix + 'tls_allowInsecure', true);
			if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
				opt.set(dom_prefix + 'tls_allowInsecure', false);
			}
			if (hash) {
				opt.set('remarks', decodeURIComponent(hash.substr(1)));
			}
		}
		if (ssu[0] === "anytls") {
			if (has_singbox) {
				dom_prefix = "singbox_"
				opt.set('type', "sing-box");
			}
			opt.set(dom_prefix + 'protocol', "anytls");
			var m = parseNodeUrl(ssrurl);
			var password = m.passwd;
			if (password === "") {
				s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
				return false;
			}
			opt.set(dom_prefix + 'password', password);
			opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
			opt.set(dom_prefix + 'port', m.port || "443");
			var queryParam = {};
			if (m.search.length > 1) {
				var query = m.search.replace('/?', '?').split('?')
				var queryParams = query[1];
				var queryArray = queryParams.split('&');
				var params;
				for (i = 0; i < queryArray.length; i++) {
					params = queryArray[i].split('=');
					queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
				}
			}
			if ((!queryParam.security || queryParam.security == "") && queryParam.sni && queryParam.sni != "") {
				queryParam.security = "tls";
			}
			if (queryParam.security) {
				if (queryParam.security == "tls") {
					opt.set(dom_prefix + 'tls', true);
					opt.set(dom_prefix + 'reality', false);
					opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
					opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
					opt.set(dom_prefix + 'tls_allowInsecure', true);
					if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
						opt.set(dom_prefix + 'tls_allowInsecure', false);
					}
					if (queryParam.fp && queryParam.fp.trim() != "") {
						opt.set(dom_prefix + 'utls', true);
						opt.set(dom_prefix + 'fingerprint', queryParam.fp);
					}
				}
				if (queryParam.security == "reality") {
					opt.set(dom_prefix + 'tls', true);
					opt.set(dom_prefix + 'reality', true);
					opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
					opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
					if (queryParam.fp && queryParam.fp.trim() != "") {
						opt.set(dom_prefix + 'utls', true);
						opt.set(dom_prefix + 'fingerprint', queryParam.fp);
					}
					opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
					opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
				}
			}
			if (m.hash) {
				opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
			}
		}
		if (dom_prefix && dom_prefix != null) {
			if (opt.get(dom_prefix + 'port').value) {
				opt.get(dom_prefix + 'port').focus();
				opt.get(dom_prefix + 'port').blur();
			}
		} else {
			s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>: " + ssu[0];
			return false;
		}
		s.innerHTML = "<font color='green'><%:Import Finished %></font>";
		return false;
	}

	function exportConfigFile(btn, sid) {
		window.open('<%=api.url("gen_client_config")%>?id=' + sid, "_blank")
	}

//]]></script>
<input type="button" class="btn cbi-button cbi-button-apply" value='<%:From Share URL%>' onclick="return fromUrl(this, '<%=self.option%>', '<%=self.value%>')" />
<input type="button" class="btn cbi-button cbi-button-apply" value='<%:Build Share URL%>' onclick="return exportUrl(this, '<%=self.option%>', '<%=self.value%>')" />
<input type="button" class="btn cbi-button cbi-button-apply" value='<%:Generate QRCode%>' onclick="return genQrcode(this, '<%=self.option%>', '<%=self.value%>')" />
<input type="button" class="btn cbi-button cbi-button-apply" value='<%:Export Config File%>' onclick="return exportConfigFile(this, '<%=self.value%>')" />
<div id="qrcode_div" style="margin-top: 1rem;display:none">
	<div id="qrcode"></div>
</div>
<span id="<%=self.option%>-status"></span>
<%+cbi/valuefooter%>
